var each = Array.prototype.forEach;

type Options = {
  properties?: string[],
  recursive?: boolean
}



function computedStyleToInlineStyle(element: SVGSVGElement, options: Options = {}) {
  let _context2


  if (!element) {
    throw new Error("No element specified.");
  }

  if (options.recursive) {
    var _context;
    (_context = element.children, each).call(_context, function (child) {
      computedStyleToInlineStyle(child, options);
    });
  }

  var computedStyle = getComputedStyle(element);
  (_context2 = options.properties || computedStyle, each).call(_context2, function (property) {
    element.style[property] = computedStyle.getPropertyValue(property);
  });
}


export default function (blockId: string): Promise<string> {
  // Not sure any better way to access the scratch-blocks workspace than this...
  const block = Blockly.getMainWorkspace().getBlockById(blockId) as Blockly.BlockSvg__Class
  const blockSvg = block.getSvgRoot().cloneNode(true /* deep */) as SVGElement

  // Once we have the cloned SVG, do the rest in a setTimeout to prevent
  // blocking the drag end from finishing promptly.
  return new Promise(resolve => {
    setTimeout(() => {
      // Strip &nbsp; entities that cannot be inlined
      blockSvg.innerHTML = blockSvg.innerHTML.replace(/&nbsp;/g, ' ');

      // Create an <svg> element to put the cloned blockSvg inside
      const NS = 'http://www.w3.org/2000/svg';
      const svg = document.createElementNS(NS, 'svg');
      svg.appendChild(blockSvg);

      // Needs to be on the DOM to get CSS properties and correct sizing
      document.body.appendChild(svg);

      const padding = 10;
      const extraHatPadding = 16;
      const topPadding = padding + (blockSvg.getAttribute('data-shapes') === 'hat' ? extraHatPadding : 0);
      const leftPadding = padding;
      blockSvg.setAttribute('transform', `translate(${leftPadding} ${topPadding})`);

      const bounds = blockSvg.getBoundingClientRect();
      svg.setAttribute('width', bounds.width + (2 * padding) + '');
      svg.setAttribute('height', bounds.height + (2 * padding + ''));

      // We need to inline the styles set by CSS rules because
      // not all the styles are set directly on the SVG. This makes the
      // image styled the same way the block actually appears.
      // TODO this doesn't handle images that are xlink:href in the SVG
      computedStyleToInlineStyle(svg, {
        recursive: true,
        // Enumerate the specific properties we need to inline.
        // Specifically properties that are set from CSS in scratch-blocks
        properties: ['fill', 'font-family', 'font-size', 'font-weight']
      });

      const svgString = (new XMLSerializer()).serializeToString(svg);

      // Once we have the svg as a string, remove it from the DOM
      svg?.parentNode?.removeChild(svg);

      resolve(`data:image/svg+xml;utf-8,${encodeURIComponent(svgString)}`);
    }, 10);
  });
}
